// Package middleware
// @Link  https://github.com/bufanyun/hotgo
// @Copyright  Copyright (c) 2023 HotGo CLI
// @Author  Ms <133814250@qq.com>
// @License  https://github.com/bufanyun/hotgo/blob/master/LICENSE
package middleware

import (
	"context"
	"rewords-server-2024/internal/global"
	"rewords-server-2024/internal/library/ecode"
	"rewords-server-2024/internal/library/response"
	"rewords-server-2024/utility/validate"
	"time"

	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/net/ghttp"
	"github.com/gogf/gf/v2/util/gconv"

	"reflect"
)

const (
	maxRequestSize      = 10 << 20 // 10MB
	defaultTimeout      = 10 * time.Second
	expectedInputParams = 2
)

// PreFilter 请求输入预处理
// api使用gf规范路由并且XxxReq结构体实现了validate.Filter接口即可
func (s *sMiddleware) PreFilter(r *ghttp.Request) {
	// 添加请求上下文超时控制
	ctx, cancel := context.WithTimeout(r.Context(), defaultTimeout)
	defer cancel()

	r.SetCtx(ctx) // GoFrame 提供的设置上下文方法

	router := global.GetRequestRoute(r)
	if router == nil {
		r.Middleware.Next()
		return
	}

	// 添加函数基本信息验证
	if router.Handler == nil {
		r.Middleware.Next()
		return
	}

	funcInfo := router.Handler.Info
	if funcInfo.Type.NumIn() != expectedInputParams {
		r.Middleware.Next()
		return
	}

	// 添加请求大小限制
	if r.ContentLength > maxRequestSize {
		response.JsonExit(r, ecode.InvalidRequestFormat.Code(), "请求体超过最大限制", nil)
		return
	}

	// 创建输入对象
	inputType := funcInfo.Type.In(1)
	var inputObject reflect.Value
	if inputType.Kind() == reflect.Ptr {
		inputObject = reflect.New(inputType.Elem())
	} else {
		inputObject = reflect.New(inputType.Elem()).Elem()
	}

	// 解析请求参数
	if err := r.Parse(inputObject.Interface()); err != nil {
		resp := gerror.Code(err)
		response.JsonExit(r, resp.Code(), "参数解析失败: "+gerror.Current(err).Error(), resp.Detail())
		return
	}

	// 检查是否实现了 Filter 接口
	filter, ok := inputObject.Interface().(validate.Filter)
	if !ok {
		r.Middleware.Next()
		return
	}

	// 执行预处理
	if err := validate.PreFilter(ctx, filter); err != nil {
		resp := gerror.Code(err)
		response.JsonExit(r, resp.Code(), "预处理失败: "+gerror.Current(err).Error(), resp.Detail())
		return
	}

	// 转换并设置参数
	params := gconv.Map(inputObject.Interface())
	if params == nil {
		response.JsonExit(r, ecode.InvalidRequestFormat.Code(), "参数转换失败", nil)
		return
	}
	r.SetParamMap(params)

	r.Middleware.Next()
}
